#pragma once
#include <windows.h>
#include <type_traits>
#include "NewObject.h"


template <typename T>
class BuilderBase {
public:
	// none of these methods must be implemented inline because it's important that their
	// implementation be hidden from the public headers.
	template<typename ... ARGS>
	explicit BuilderBase(ARGS&& ...) noexcept;
	BuilderBase() noexcept;
	~BuilderBase() noexcept;
	BuilderBase(BuilderBase const& rhs) noexcept;
	BuilderBase& operator = (BuilderBase const& rhs) noexcept;

	// move ctor and copy operator can be implemented inline and don't need to be exported
	BuilderBase(BuilderBase&& rhs) noexcept : mImpl(rhs.mImpl) { rhs.mImpl = nullptr; }

	BuilderBase& operator = (BuilderBase&& rhs) noexcept {
		auto temp = mImpl;
		mImpl = rhs.mImpl;
		rhs.mImpl = temp;
		return *this;
	}

protected:
	T* mImpl = nullptr;
	inline T* operator->() noexcept { return mImpl; }
	inline T const* operator->() const noexcept { return mImpl; }
};



template<typename T>
BuilderBase<T>::BuilderBase() noexcept
	: mImpl(NewObject<T>()) {
}

template<typename T>
template<typename ... ARGS>
BuilderBase<T>::BuilderBase(ARGS&& ... args) noexcept
	: mImpl(NewObject<T>(std::forward<ARGS>(args)...)) {
}

template<typename T>
BuilderBase<T>::~BuilderBase() noexcept {
	DeleteObject<T>(mImpl);
}

template<typename T>
BuilderBase<T>::BuilderBase(BuilderBase const& rhs) noexcept
	: mImpl(NewObject<T>(*rhs.mImpl)) {
}

template<typename T>
BuilderBase<T>& BuilderBase<T>::operator=(BuilderBase<T> const& rhs) noexcept {
	*mImpl = *rhs.mImpl;
	return *this;
}




#if 0

template <typename T>
class BuilderBase {
public:
	// none of these methods must be implemented inline because it's important that their
	// implementation be hidden from the public headers.
	BuilderBase() noexcept;
	~BuilderBase() noexcept;
	BuilderBase(BuilderBase const& rhs) noexcept;
	BuilderBase& operator = (BuilderBase const& rhs) noexcept;

	// move ctor and copy operator can be implemented inline and don't need to be exported
	BuilderBase(BuilderBase&& rhs) noexcept { mImpl = rhs.mImpl; }

	BuilderBase& operator = (BuilderBase&& rhs) noexcept {
		auto temp = mImpl;
		mImpl = rhs.mImpl;
		rhs.mImpl = temp;
		return *this;
	}

protected:
	T mImpl;
	inline T& operator->() noexcept { return mImpl; }
	inline T& const operator->() const noexcept { return mImpl; }
};



template<typename T>
BuilderBase<T>::BuilderBase() noexcept
{
}

template<typename T>
BuilderBase<T>::~BuilderBase() noexcept {
}

template<typename T>
BuilderBase<T>::BuilderBase(BuilderBase const& rhs) noexcept
{
	mImpl = rhs.mImpl;
}

template<typename T>
BuilderBase<T>& BuilderBase<T>::operator=(BuilderBase<T> const& rhs) noexcept {
	mImpl = rhs.mImpl;
	return *this;
}

#endif
